import WebGl from '@/modules/three';
// import fontJson from 'three/examples/fonts/helvetiker_regular.typeface.json'
const fontJson = require('three/examples/fonts/helvetiker_regular.typeface.json');
const { Three, TWEEN, dat, Stats, OrbitControls, FontLoader, TextGeometry } =
  WebGl;

class WebGlControl {
  private container: any;
  private camera: any;
  private scene: any;
  private renderer: any;
  private controls: any;
  private stats: any;
  private animateFrame: any;
  private group: any; //地球所在的组
  private cubeGroup: any; //

  private Geometrys: {
    planeGeometry?: any;
    lineGeometry?: any;
    cubeGeometry?: any;
    textGeometry?: any;
  } = {}; //保存所有Geometry，方便统一销毁
  private Materials: {
    planeMaterial?: any;
    lineMaterial?: any;
    cubeMaterial?: any;
    textMaterial?: any;
  } = {}; //保存所有Material，方便统一销毁

  private GuiInit: any = null;
  private guiData: any = {
    x: 0.005,
    color: '#fafafa',
    autoRotate: true,
  };

  public init = () => {
    // if(this.scene) {return}
    this.container = document.getElementById('WebGL-output-test');
    let width = this.container.clientWidth,
      height = this.container.clientHeight;

    this.scene = new Three.Scene();

    this.camera = new Three.PerspectiveCamera(60, width / height, 0.1, 100);
    this.camera.position.x = 0;
    this.camera.position.y = 1;
    this.camera.position.z = 4;
    this.camera.lookAt(this.scene.position);

    this.renderer = new Three.WebGLRenderer();
    // this.renderer.setClearColor( 0xffffff );
    this.renderer.setPixelRatio(window.devicePixelRatio);
    this.renderer.setSize(width, height);
    this.renderer.shadowMap.enabled = true;
    // this.renderer.shadowMap.type = Three.BasicShadowMap;
    this.container.appendChild(this.renderer.domElement);

    this.controls = new OrbitControls(this.camera, this.renderer.domElement);

    this.addThings();
    this.addLight(); //+光源
    this.animate(); //开始动
    this.initStats();

    this.initGui();
  };
  public destroy = () => {
    this.toggleGui(0);
    Object.values(this.Geometrys).forEach((e) => {
      e.dispose();
    });
    Object.values(this.Materials).forEach((e) => {
      e.dispose();
    });
    this.scene.clear();
    this.renderer.dispose();
    this.renderer.forceContextLoss();
    this.camera = null;
    this.scene = null;
    this.renderer = null;
    this.GuiInit = null;
    this.stats = null;
    cancelAnimationFrame(this.animateFrame);
  };

  private initStats = () => {
    this.stats = new Stats();
    this.stats.showPanel(0); // 0: fps, 1: ms, 2: mb, 3+: custom
    this.stats.dom.style.position = 'absolute';
    this.container.appendChild(this.stats.dom);
  };

  public initGui = () => {
    if (this.GuiInit) {
      this.toggleGui();
      return;
    }
    this.GuiInit = new dat.GUI({
      // autoPlace: false
    });

    this.GuiInit.domElement.style.position = 'absolute';
    this.GuiInit.domElement.style.right = '10px';
    this.GuiInit.domElement.style.top = '10px';

    let GuiController = this.GuiInit.addFolder('控制窗口');
    GuiController.add(this.guiData, 'x', -0.1, 0.1, 0.005).name('自转速度');
    GuiController.addColor(this.guiData, 'color').name('背景颜色');
    GuiController.open();

    let cubeGui = this.GuiInit.addFolder('cube position');
    cubeGui.add(this.cubeGroup.position, 'x', -100, 100, 1);
    cubeGui.add(this.cubeGroup.position, 'y', -100, 100, 1);
    cubeGui.add(this.cubeGroup.position, 'z', -100, 100, 1);
    cubeGui.open();

    let cubeGuiRotate = this.GuiInit.addFolder('cube rotation');
    cubeGuiRotate.add(this.guiData, 'autoRotate').name('自动旋转');
    cubeGuiRotate.add(this.cubeGroup.rotation, 'x', -3.14, 3.14, 0.01);
    cubeGuiRotate.add(this.cubeGroup.rotation, 'y', -3.14, 3.14, 0.01);
    cubeGuiRotate.add(this.cubeGroup.rotation, 'z', -3.14, 3.14, 0.01);
    //rotation是欧拉类型的值，单位是π；比如让物体按Y轴正方向旋转45°可以写成 object3D.rotation.y+=0.25*Math.PI
    cubeGuiRotate.open();
  };

  public toggleGui = (state: any = null) => {
    if (!this.GuiInit || !this.GuiInit.domElement) {
      return;
    }
    let display = this.GuiInit.domElement.style.display == 'none' ? '' : 'none';
    if (state == 0) {
      display = 'none';
    }
    this.GuiInit.domElement.style.display = display;
  };

  private addLight = () => {
    let ambi = new Three.AmbientLight(0x686868);
    this.scene.add(ambi);

    let direLight = new Three.DirectionalLight(0xff0000);
    direLight.position.set(10, 10, 5);
    direLight.intensity = 0.8;
    direLight.castShadow = true;
    //     // 设置阴影相关属性
    direLight.shadow.mapSize.width = 1920; // 阴影贴图的宽度
    direLight.shadow.mapSize.height = 1920; // 阴影贴图的高度
    direLight.shadow.camera.near = 0.1; // 阴影摄像机的近裁剪面
    direLight.shadow.camera.far = 30; // 阴影摄像机的远裁剪面
    direLight.shadow.radius = 10; //设置阴影贴图模糊度
    this.scene.add(direLight);

    // let light = new Three.PointLight(0xffff00);
    // light.position.set(-100, 100, 0);
    // this.scene.add(light);

    // const spotLight = new Three.SpotLight( 0xffffff );
    // 		spotLight.name = 'Spot Light';
    // 		spotLight.angle = Math.PI / 5;
    // 		spotLight.penumbra = 0.3;
    // 		spotLight.position.set( -10, 10, 5 );
    // 		spotLight.castShadow = true;
    // 		spotLight.shadow.camera.near = 8;
    // 		spotLight.shadow.camera.far = 30;
    // 		spotLight.shadow.mapSize.width = 1024;
    // 		spotLight.shadow.mapSize.height = 1024;
    // 		this.scene.add( spotLight );
  };

  private addThings = () => {
    const axesHelper = new Three.AxesHelper(800);
    this.scene.add(axesHelper); //添加坐标轴；红线是X轴，绿线是Y轴，蓝线是Z轴

    /** 地球 **/
    this.group = new Three.Group(); //地球组合
    this.scene.add(this.group);
    // let loader = new Three.TextureLoader();
    // let planetTexture = require("@/assets/aa.jpg");
    // loader.load( planetTexture, texture => {
    //     let geometry = new Three.SphereGeometry( 50, 20, 20 );
    //     let material = new Three.MeshBasicMaterial( { map: texture, overdraw: 0.5 } );
    //     let mesh = new Three.Mesh( geometry, material );
    //     mesh.position.set(0, 50, 0);
    //     this.group.add( mesh );
    // });
    /** 地球 **/

    /** 平面 **/
    this.Geometrys.planeGeometry = new Three.PlaneGeometry(4, 4, 1, 1);
    // this.Materials.planeMaterial = new Three.MeshBasicMaterial({color: 0xffff00, side: Three.DoubleSide})
    this.Materials.planeMaterial = new Three.MeshPhongMaterial({
      color: 0xeaeaef,
      // wireframe: true,
    });
    //wireframe:  显示为网格
    const plane = new Three.Mesh(
      this.Geometrys.planeGeometry,
      this.Materials.planeMaterial,
    );
    plane.rotation.x = -1;
    // plane.castShadow = true;
    plane.receiveShadow = true;
    this.scene.add(plane);
    /** 平面 **/

    /** 线段 **/
    this.Materials.lineMaterial = new Three.LineBasicMaterial({
      color: 0x0000ff,
    }); //线材质
    const points = [];
    points.push(new Three.Vector3(-1, 0, 0));
    points.push(new Three.Vector3(0, 2, 0));
    points.push(new Three.Vector3(1, 0, 0));
    this.Geometrys.lineGeometry = new Three.BufferGeometry().setFromPoints(
      points,
    ); //定义一个3个点的缓冲类几何
    const line = new Three.Line(
      this.Geometrys.lineGeometry,
      this.Materials.lineMaterial,
    );
    this.scene.add(line);
    /** 线段 **/

    this.cubeGroup = new Three.Group();
    this.scene.add(this.cubeGroup);
    /** 立方体 **/
    this.Geometrys.cubeGeometry = new Three.BoxGeometry(1, 1, 1);
    this.Materials.cubeMaterial = new Three.MeshPhongMaterial({
      color: 0xfd59d7,
    });
    const cube = new Three.Mesh(
      this.Geometrys.cubeGeometry,
      this.Materials.cubeMaterial,
    );
    cube.castShadow = true;
    cube.receiveShadow = true;
    this.cubeGroup.add(cube);
    /** 立方体 **/

    /** 文字 **/
    const textLoader = new FontLoader();
    textLoader.load('../../helvetiker_regular.typeface.json', (font: any) => {
      this.Geometrys.textGeometry = new TextGeometry('Kay Awsome!!!', {
        font: font,
        size: 0.2,
        height: 0.1,
        curveSegments: 12,
        bevelEnabled: false,
        bevelThickness: 5,
        bevelSize: 2,
        bevelSegments: 5,
      });
      this.Geometrys.textGeometry.computeBoundingBox();
      this.Materials.textMaterial = new Three.MeshPhongMaterial({
        color: 0x0be8df,
        flatShading: true,
      }); // front
      const textMesh = new Three.Mesh(
        this.Geometrys.textGeometry,
        this.Materials.textMaterial,
      );
      textMesh.position.set(-1, 1, 0);
      textMesh.receiveShadow = true;
      textMesh.castShadow = true;
      this.cubeGroup.add(textMesh);
    });
    /** 文字 **/

    this.initTween();
  };

  private initTween = () => {
    var tween = new TWEEN.Tween(this.cubeGroup.position)
      .to({ x: 1 }, 1000)
      .start();
  };

  private animate = () => {
    // if(!this.renderer){return;}
    if (this.stats) {
      this.stats.begin();
    }

    this.render();
    TWEEN.update();
    this.controls.update();

    if (this.stats) {
      this.stats.end();
    }
    this.animateFrame = requestAnimationFrame(this.animate);
  };
  private render = () => {
    this.renderer.setClearColor(this.guiData.color, 1.0);
    this.group.rotation.y -= this.guiData.x;
    if (this.guiData.autoRotate) {
      this.cubeGroup.rotation.x += this.guiData.x;
      this.cubeGroup.rotation.y += this.guiData.x;
    }
    this.renderer.render(this.scene, this.camera);
  };
}

const webGlControl = new WebGlControl();
export default webGlControl;
